package com.zzy.other;

import java.util.Stack;

/**
 * 316. 去除重复字母 中等
 * 给你一个字符串 s ，请你去除字符串中重复的字母，使得每个字母只出现一次。
 * 需保证 返回结果的字典序最小（要求不能打乱其他字符的相对位置）。
 * 示例 1：
 * 输入：s = "bcabc"
 * 输出："abc"
 * 示例 2：
 * 输入：s = "cbacdcbc"
 * 输出："acdb"
 */
public class L316removeDuplicateLetters {
    public static void main(String[] args) {
        //String s = "bcabc";
        String s = "cbacdcbc";
        System.out.println(removeDuplicateLetters(s));
    }

    public static String removeDuplicateLetters(String s) {
        //需要提前确定1.弹栈的时候，后边还有没有该数，没有就不能弹
        //2.进栈的时候，栈里有没有该数，有就不能进

        int len = s.length();

        //每个字母出现的次数
        int[] count = new int[26];
        for (int i = 0; i < len; i++) {
            count[s.charAt(i) - 'a']++;
        }

        //每个字母是否出现在栈里
        boolean[] exist = new boolean[26];
        //单增栈
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            //这样后边就还有count[c-'a']个c
            count[c - 'a']--;

            //重要！栈中已存在的数要略过
            if (exist[c - 'a']) {
                continue;
            }
            while (!stack.isEmpty() && stack.peek() > c) {
                if (count[stack.peek() - 'a'] == 0) {
                    //后边没栈顶元素了，不能弹
                    break;
                }
                char pop = stack.pop();
                exist[pop - 'a'] = false;
            }
            if (!exist[c - 'a']) {
                //如果栈里有c，则c不能进栈
                stack.push(c);
                exist[c - 'a'] = true;
            }
        }

        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()) {
            sb.append(stack.pop());
        }
        return sb.reverse().toString();
    }
}








